/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package compilador.AnalisadorSemantico;

import compilador.AnalisadorSintatico.SM_CMD_Atrib;
import compilador.AnalisadorSintatico.SM_CMD_Switch;
import compilador.AnalisadorSintatico.SubMaquina;

/**
 * MVN
 * 
 * Pseudo-instrucoes
 * @ - Recebe um operando numerico, define o end. da instrucao seguinte
 * K - Constante, o operando numerico tem o valor da constante (em hexa)
 * $ - Reserva de area de dados, o operando numerico define o tamanho da area a ser reservada
 * # - Final fisico do texto fonte
 * 
 * & - Origem relocavel
 * < - Endereco simbolico de entrada (entry point)
 * > - Endereco simbolico externo (external)
 * 
 * 
 * Instrucoes MVN
 * 
 * 0  JP - Jump
 * 1  JZ - Jump if Zero
 * 2  JN - Jump if Negative
 * 3  LV - Load Value
 * 4  +  - Add
 * 5  -  - Subtract
 * 6  *  - Multiply
 * 7  /  - Divide
 * 8  LD - Load
 * 9  MM - Move do Memory
 * A  SC - Subroutine Call
 * B  RS - Return from Subroutine
 * C  HM - Halt Machine
 * D  GD - Get Data
 * E  PD - Put Data
 * F  OS - Operating System
 * 
 * 
 * 
 * AREAS DE CODIGO
 * 1. Constantes
 * 3. Run Time Environment
 * 4. Pilha de execução
 * 5. Codigo
 * 
 * 
 * 
 * @author Leles
 */
public class GeracaoDeCodigo {

    /*public enum MNM {
    JP, JZ, JN, LV, +
    }*/
    
    /* Contador de labels:
     * . Cada vez que uma estrutura e utilizada, labels precisam ser usadas
     *   para controlar o fluxo
     * . O que se faz aqui e contabilizar quantas vezes uma label ja foi usada
     *   e deste modo poder criar um nome unico para cada uma.
     */ 
    public enum Labels {
        PROG_INIC, PROG_SAI,
        CmdIF_THEN_, CmdIF_NOT_THEN_, CmdIF_SAI_ELSE_,
        CmdSW_INICIO_, CmdSW_CASE_, CmdSW_SAI_,
        WHILE_INIC_, WHILE_SAI_,
        DOWHILE_INIC_, DOWHILE_SAI_,
        FOR_, FOR_SAI_,
        FUNCTION_, FUNCTION_SAI_
    }   
    
    public int tmpVar =0;
    public int labelCount = 0;
    
    int [] ConstantesJaUsadas;
    
    String RTE_Inicio_Prog = "";
    String Constantes = "";
    String Codigo = "";
    
    public enum TiposAS {
        ACAO_NENHUMA,
        INICIO_PROGRAMA, FIM_PROGRAMA,
        ABRE_FUNCTION, RETURN, RETURN_VALOR, FECHA_FUNCTION,
        ATRIB_RecebeVar, ATRIB_FIM,
        CONDICAO, 
        IF_THEN, IF_ELSE, IF_END_WITHELSE, IF_END_NOELSE,
        SWITCH_INICIO, SWITCH_CASE, SWITCH_BREAK, SWITCH_FIM,
        WHILE_INICIO, WHILE_DECIDE ,WHILE_FIM,
        DOWHILE_INICIO, DOWHILE_FIM
        
    } 
    
    public void AcaoSemantica (TiposAS t, int Nb, String Param, SubMaquina sm) {
        
        switch (t) {                
            case INICIO_PROGRAMA: 
                adicionaCodigoSemLabel("JP", Labels.PROG_INIC.toString());
                adicionaCodigoComLabel("DUMP", "K" + TAB, "/0");
                adicionaInstrucaoVazia(Labels.PROG_INIC.toString());
                break;
            case FIM_PROGRAMA:
                adicionaCodigoComLabel(Labels.PROG_SAI.toString(), "HM", "/0");
                break;
            case ABRE_FUNCTION: 
                ;
                break;
            case RETURN: 
                ;
                break;
            case RETURN_VALOR: 
                ;
                break;
            case FECHA_FUNCTION: 
                ;
                break;
                
             
            case ATRIB_RecebeVar:
                ((SM_CMD_Atrib)sm).AtribVar = Param;
                break;
            case ATRIB_FIM:
                adicionaCodigoSemLabel("MM", ((SM_CMD_Atrib)sm).AtribVar);
                break;
                
                
                
            //     
            case WHILE_INICIO:
                adicionaInstrucaoVazia(Labels.WHILE_INIC_.toString() + Nb);
                break;
            case WHILE_DECIDE:
                adicionaCodigoSemLabel("JZ", Labels.WHILE_SAI_.toString() + Nb);
                break;
            case WHILE_FIM:
                adicionaInstrucaoVazia(Labels.WHILE_SAI_.toString() + Nb);
                break;
                
                
                
            case DOWHILE_INICIO:
                adicionaInstrucaoVazia(Labels.DOWHILE_INIC_.toString() + Nb);
                break;
            case DOWHILE_FIM:
                adicionaCodigoSemLabel("JP", Labels.DOWHILE_SAI_.toString() + Nb);
                adicionaCodigoSemLabel("JZ", Labels.DOWHILE_SAI_.toString() + Nb);
                adicionaCodigoSemLabel("JP", Labels.DOWHILE_INIC_.toString() + Nb);
                adicionaInstrucaoVazia(Labels.DOWHILE_SAI_.toString() + Nb);
                break;
                
                
            
            case CONDICAO:
                adicionaCodigoSemLabel("LV", Param);
                break;
                
                
                
                
            // IF
            case IF_THEN: 
                adicionaCodigoSemLabel("JZ", Labels.CmdIF_NOT_THEN_.toString()+Nb);
                break;
            case IF_ELSE: 
                adicionaCodigoSemLabel("JP", Labels.CmdIF_SAI_ELSE_.toString() + Nb);
                adicionaInstrucaoVazia(Labels.CmdIF_SAI_ELSE_.toString() + Nb);
                break;
            case IF_END_WITHELSE:
                adicionaInstrucaoVazia(Labels.CmdIF_SAI_ELSE_.toString()+Nb);
                break;
            case IF_END_NOELSE:
                adicionaInstrucaoVazia(Labels.CmdIF_NOT_THEN_.toString()+Nb);
                break;
                
                
                
            case SWITCH_INICIO:
                ((SM_CMD_Switch) sm).SwitchVar = Param;
                adicionaCodigoSemLabel("JP", Labels.CmdSW_INICIO_.toString() + Nb);
                break;
            case SWITCH_CASE:
                adicionaInstrucaoVazia(Labels.CmdSW_CASE_.toString() + Nb + "_" + Param);
                ((SM_CMD_Switch) sm).Cases.offer(Param);
                break;
            case SWITCH_BREAK:
                adicionaCodigoSemLabel("JP", Labels.CmdSW_SAI_.toString() + Nb);
                break;
            case SWITCH_FIM:
                adicionaCodigoSemLabel("JP", Labels.CmdSW_SAI_.toString() + Nb);
                adicionaInstrucaoVazia(Labels.CmdSW_INICIO_.toString() + Nb);
                String c; 
                while (((SM_CMD_Switch) sm).Cases.peek() != null) {
                    c = ((SM_CMD_Switch) sm).Cases.poll();
                    adicionaCodigoSemLabel("LV", c);
                    adicionaCodigoSemLabel("-" + TAB, ((SM_CMD_Switch) sm).SwitchVar);
                    adicionaCodigoSemLabel("JZ", Labels.CmdSW_CASE_.toString() + Nb + "_" + c);
                }
                adicionaInstrucaoVazia(Labels.CmdSW_SAI_.toString() + Nb);
                break;
        }
    }
    
    static String NL = "\n";
    static String TAB = "\t";
    static String TABn = "\t\t\t\t\t";
    static String TABn2 = TABn + "\t\t";
    static String INSTRUCAO_VAZIA = "MM" + TAB + "DUMP";
    
    private void adicionaCodigo (String s) {
        Codigo = Codigo.concat(s);
    }
    
    private int Tab = 30;
    
    private void adicionaCodigoSemLabel (String mnm, String op) {
        Codigo = Codigo.concat(String.format("%-" + Tab + "s%s%s", "", mnm + TAB, op + NL));
    }
    private void adicionaCodigoComLabel (String lbl, String mnm, String op) {
        Codigo = Codigo.concat(String.format("%-" + Tab + "s%s%s", lbl, mnm + TAB, op + NL));
    }
    private void adicionaInstrucaoVazia (String lbl) {
        Codigo = Codigo.concat(String.format("%-" + Tab + "s%s", lbl, INSTRUCAO_VAZIA + NL));
    }
    
    private void VerificaEAdicionaConstante (String s) {
        Constantes = Constantes + s;
    }
    
    private void RTEAdicionaPosicaoMemoria(String nome, int valorInicial) {
        RTE_Inicio_Prog.concat(String.format("%-" + Tab + "s%s%s", nome, "K" + TAB, valorInicial + NL));
    }
    
    public GeracaoDeCodigo() {
        //labels = new int[Lbl.class.getEnumConstants().length];
    }
    
    
    
}
